﻿using Grow.Domain.DomainRepository;
using Grow.Domain.EventBus;
using Grow.Module.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Grow.EventBus.Cap.PublisherDomainEvents
{
    public class PublisherDomainEventService : IPublisherDomainEventService
    {

        private readonly IServiceContext _serviceContext;
        private readonly DomainEventBusOptions _eventBusOptions;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IPublisherDomainEventRepository _publisherDomainEventRepository;
        public PublisherDomainEventService(IServiceContext serviceContext)
        {
            _serviceContext = serviceContext;
            _eventBusOptions = _serviceContext.GetOptions<DomainEventBusOptions>();
            _unitOfWorkManager = _serviceContext.GetRequiredService<IUnitOfWorkManager>();
            _publisherDomainEventRepository = _serviceContext.GetRequiredService<IPublisherDomainEventRepository>();
        }

        public async Task<bool> LockPublisherEventAsync(Guid Id, CancellationToken cancellationToken)
        {
            var now = DateTimeOffset.Now;
            var lockEndTime = DateTimeOffset.Now.AddSeconds(_eventBusOptions.LockTime);
            var unitOfWork = _unitOfWorkManager.GetUnitOfWork();

            var publisherDomainEvent = await _publisherDomainEventRepository.FirstOrDefaultAsync(a =>
                 a.Id == Id
                && (a.LockEndTime < now || a.LockEndTime == null),cancellationToken);

            if (publisherDomainEvent is null)
            {
                return false;
            }
            publisherDomainEvent.LockEndTime = lockEndTime;
            await _publisherDomainEventRepository.UpdateAsync(publisherDomainEvent, cancellationToken);

            await unitOfWork.CommitAsync(cancellationToken);
            return true;
        }

        public  async Task UpdatePublisherEventAsync(Guid Id, PublisherDomainEventStatus publisherDomainEventStatus, CancellationToken cancellationToken)
        {

            var unitOfWork = _unitOfWorkManager.GetUnitOfWork();

            var publisherDomainEvent = await _publisherDomainEventRepository.FirstOrDefaultAsync(a =>
                a.Id == Id
               ,cancellationToken);

            if (publisherDomainEvent is null)
            {
                return;
            }
            publisherDomainEvent. EventStatus = publisherDomainEventStatus;
            publisherDomainEvent.RetryCount++;
            if (publisherDomainEventStatus == PublisherDomainEventStatus.Success)
            {
                publisherDomainEvent.ExpireTime = DateTimeOffset.Now.AddHours(_eventBusOptions.SucceedExpireHour);
            }
            await _publisherDomainEventRepository.UpdateAsync(publisherDomainEvent, cancellationToken);

            await unitOfWork.CommitAsync(cancellationToken);
        }
    }
}
